﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.IO;
using System.ComponentModel;

namespace Streambolics.PtBurn
{
    /// <summary>
    ///     A PtBurn job.
    /// </summary>
    /// <remarks><para>
    ///     This object represents both jobs that are already
    ///     in the queue, and jobs currently being built by the
    ///     current application.
    /// </para><para>
    ///     You can't create a job using the constructor. To
    ///     create a job, call the Create() method of a 
    ///     PtBurnJobServer.
    /// </para></remarks>

    public class PtBurnJob
    {
        private string _Name;
        private PtBurnJobServer _Client;
        private PtBurnJobStatus _Status = PtBurnJobStatus.NotInQueue;
        private bool _FoundInQueue = false;
        private FileInfo _IsoFile;
        private FileInfo _CoverFile;
        private List<FileInfo> _Files;
        private List<DirectoryInfo> _Directories;

        internal PtBurnJob (PtBurnJobServer aClient, string aName)
        {
            Contract.Requires (aClient != null);
            Contract.Requires (!String.IsNullOrEmpty (aName));

            _Name = aName;
            _Client = aClient;
            _Client.Add (this);
        }

        /// <summary>
        ///     The name of the job.
        /// </summary>
        /// <remarks><para>
        ///     The name of a job is its unique identifier
        ///     for the server, so duplicate names are not
        ///     allowed.
        /// </para><para>
        ///     Job name must be a valid file or directory
        ///     name, so limitations apply. Call IsValidJobName
        ///     in PtBurnTools to validate a job name.
        /// </para></remarks>

        [Category ("Identity")]
        public string Name
        {
            get
            {
                return _Name;
            }
        }

        [Category ("Building")]
        public string StatusText
        {
            get
            {
                return PtBurnTools.StatusToString (Status);
            }
        }

        [Category ("Building")]
        public PtBurnJobStatus Status
        {
            get
            {
                return _Status;
            }
            internal set
            {
                _Status = value;
                _FoundInQueue = true;
            }
        }

        internal void BeginUpdateStatus ()
        {
            _FoundInQueue = false;
        }

        internal void EndUpdateStatus ()
        {
            if (!_FoundInQueue && !Local)
            {
                Status = PtBurnJobStatus.NotInQueue;
            }
        }

        [Category ("Building")]
        public bool Local
        {
            get
            {
                return _Status < PtBurnJobStatus.Submitted;
            }
        }

        internal DirectoryInfo JobDirectory
        {
            get
            {
                // TODO : Should cache this as it is used a lot
                return _Client.Directory.Subdirectory (Name);
            }
        }

        internal DirectoryInfo ContentDirectory
        {
            get
            {
                return JobDirectory.Subdirectory ("Content");
            }
        }

        /// <summary>
        ///     Submits the job to the queue.
        /// </summary>

        public void Submit ()
        {
            Contract.Requires (Status == PtBurnJobStatus.Building);

            Status = PtBurnJobStatus.Submitting;

            // TODO : create the jobfile
            StringList sl = new StringList ();

            sl.Add ("JobID=" + Name);
            sl.Add ("ClientID=" + Name);
            sl.Add ("DeleteFiles=YES");
            if (_CoverFile != null)
            {
                sl.Add ("PrintLabel=" + ServerFileName (_CoverFile));
            }
            else
            {
                // TODO : Build a suitable label file
            }

            if (_IsoFile != null)
            {
                sl.Add ("ImageFile=" + ServerFileName (_IsoFile));
            }
            else
            {
                // TODO : Copy files to server
                sl.Add ("Data=" + ContentDirectory);
            }
            sl.SaveToFile (_Client.Directory + Name + ".JRQ");
            Status = PtBurnJobStatus.Submitted;
        }

        /// <summary>
        ///     The name that the server would use to refer to the given
        ///     file.
        /// </summary>
        /// <param name="aLocalFile">
        ///     The local file to use.
        /// </param>
        /// <returns>
        ///     A string representing the path the server would use to
        ///     refer to the file.
        /// </returns>

        private string ServerFileName (FileInfo aLocalFile)
        {
            //  TODO : verify that file is accessible by server,
            //         otherwise copy it
            return aLocalFile.ToString ();
        }

        [Category ("Building")]
        [Description ("Whether the job can still be changed before submitting")]
        public bool IsBuildable
        {
            get
            {
                return Status <= PtBurnJobStatus.Building;
            }
        }

        [Category ("Building")]
        [Description ("Name of the ISO file to be used as image")]
        public FileInfo IsoFile
        {
            get
            {
                return _IsoFile;
            }
            set
            {
                Contract.Requires (IsBuildable);
                Contract.Requires (_Directories == null);
                Contract.Requires (_Files == null);
                Contract.Requires (value != null);

                _IsoFile = value;
                Status = PtBurnJobStatus.Building;
            }
        }

        private IniSection StatusSection
        {
            get
            {
                return _Client.JobSection (_Name);
            }
        }

        [Category ("PtBurn Server")]
        public string ClientID
        {
            get
            {
                return StatusSection["ClientID"].Value;
            }
        }

        [Category ("PtBurn Server")]
        [Description ("Time when job was created")]
        public string TimeCreated
        {
            get
            {
                return StatusSection["TimeCreated"].Value;
            }
        }

        [Category ("PtBurn Server")]
        [Description("Time when job was started by server")]
        public string TimeStarted
        {
            get
            {
                return StatusSection["TimeStarted"].Value;
            }
        }

        [Category ("PtBurn Server")]
        public string TimeCompleted
        {
            get
            {
                return StatusSection["TimeCompleted"].Value;
            }
        }

        /// <summary>
        ///     The status as reported by the PtBurn server itself.
        /// </summary>

        [Category ("PtBurn Server")]
        public string CurrentStatus
        {
            get
            {
                return StatusSection["CurrentStatus"].Value;
            }
        }

        [Category ("PtBurn Server")]
        [Description ("Total number of good discs produced")]
        public int GoodDiscs
        {
            get
            {
                return StatusSection["GoodDiscs"].IntegerValue;
            }
        }

        [Category ("PtBurn Server")]
        [Description ("Total number of failed discs")]
        public int BadDiscs
        {
            get
            {
                return StatusSection["BadDiscs"].IntegerValue;
            }
        }

        [Category ("PtBurn Server")]
        [Description ("Number of discs yet to be burnt for this job")]
        public int DiscsRemaining
        {
            get
            {
                return StatusSection["DiscsRemaining"].IntegerValue;
            }
        }

        [Category ("PtBurn Server")]
        [Description ("Total number of jobs scheduled before this one")]
        public int JobsAhead
        {
            get
            {
                return StatusSection["JobsAhead"].IntegerValue;
            }
        }

        /// <summary>
        ///     The number of discs left to be burnt before the 
        ///     server will start this job.
        /// </summary>

        [Category ("PtBurn Server")]
        [Description ("Total number of discs scheduled before this job starts")]
        public int DiscsAhead
        {
            get
            {
                return StatusSection["DiscsAhead"].IntegerValue;
            }
        }

        [Category ("PtBurn Server")]
        [Description ("State of the job")]
        public int JobState
        {
            get
            {
                return StatusSection["JobState"].IntegerValue;
            }
        }

        public int DiscErrorIndex (int i)
        {
            return StatusSection["DiscErrorIndex" + i.ToString ()].IntegerValue;
        }

        public int DiscErrorNumber (int i)
        {
            return StatusSection["DiscErrorNumber" + i.ToString ()].IntegerValue;
        }

        public string DiscErrorString (int i)
        {
            return StatusSection["DiscErrorString" + i.ToString ()].Value;
        }

    }
}
